
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.ObjectInputStream.GetField;
import java.util.ArrayList;

import javax.print.attribute.standard.MediaSize.Other;

import DG.Clazz;
import DG.DGFactory;
import DG.DiagClass;
import DG.Operation;
import SM.MAT;
import SM.SMFactory;
import SM.SMPackage;
import SM.State;
import SM.Transition;


public class Main {

	
	public static void main(String[] args){
		
		//Creer la state machine
		MAT mat = SMFactory.eINSTANCE.createMAT();
		
		State debut = SMFactory.eINSTANCE.createState();
		debut.setNom("Debut");
		State fin = SMFactory.eINSTANCE.createState();
		fin.setNom("Fin");
		
		State ouvert = SMFactory.eINSTANCE.createState();
		ouvert.setNom("Ouvert");
		
		State fermee = SMFactory.eINSTANCE.createState();
		fermee.setNom("Fermee");
		
		mat.getEtats().add(debut);
		mat.getEtats().add(fin);
		mat.getEtats().add(ouvert);
		mat.getEtats().add(fermee);
		
		
		
		Transition debut_ouvert = SMFactory.eINSTANCE.createTransition();
		Transition ouvert_fermee = SMFactory.eINSTANCE.createTransition();
		Transition fermee_fin = SMFactory.eINSTANCE.createTransition();
		debut_ouvert.setNom("ouvrir");
		ouvert_fermee.setNom("fermer");
		fermee_fin.setNom("fin");
		
		
		debut_ouvert.setSrc(debut);
		debut_ouvert.setTg(ouvert);
		
		ouvert_fermee.setSrc(ouvert);
		ouvert_fermee.setTg(fermee);
		
		fermee_fin.setSrc(fermee);
		fermee_fin.setTg(fin);
		
		
		
		mat.getTrans().add(debut_ouvert);
		mat.getTrans().add(ouvert_fermee);
		mat.getTrans().add(fermee_fin);
		
		
		//Fin
		
		
		//DiagClass
		
		DiagClass diag = DGFactory.eINSTANCE.createDiagClass();
		
		Clazz serveur = DGFactory.eINSTANCE.createClazz();
		serveur.setNom("Serveur");
				
		Clazz etat = DGFactory.eINSTANCE.createClazz();
		
		etat.setNom("Etat");
		diag.setSuper(etat);
		serveur.setRefclass(etat);
		etat.setRefclass(serveur);
		
		
		
		Clazz ouvertClazz = DGFactory.eINSTANCE.createClazz();
		ouvertClazz.setNom("Ouvert");
		
		Clazz fermeeClazz = DGFactory.eINSTANCE.createClazz();
		fermeeClazz.setNom("Fermee");
		
		Clazz debutClazz = DGFactory.eINSTANCE.createClazz();
		debutClazz.setNom("Debut");
		
		Clazz finClazz = DGFactory.eINSTANCE.createClazz();
		finClazz.setNom("Fin");
		
		ouvertClazz.setSuper(etat);
		fermeeClazz.setSuper(etat);
		debutClazz.setSuper(etat);
		finClazz.setSuper(etat);
		
		
		Operation op1 = DGFactory.eINSTANCE.createOperation();
		op1.setNom("ouvrir");
		
		Operation op2 = DGFactory.eINSTANCE.createOperation();
		op2.setNom("fermer");
		
		Operation op3 = DGFactory.eINSTANCE.createOperation();
		op3.setNom("fin");
		
		serveur.getOps().add(op1);
		serveur.getOps().add(op2);
		
		diag.getClazzes().add(debutClazz);
		diag.getClazzes().add(finClazz);
		diag.getClazzes().add(ouvertClazz);
		diag.getClazzes().add(fermeeClazz);
		
		
		etat.getOps().add(op1);
		etat.getOps().add(op2);
		etat.getOps().add(op3);
		
		ouvertClazz.getOps().add(op1);
		ouvertClazz.getOps().add(op2);
		ouvertClazz.getOps().add(op3);
		
		fermeeClazz.getOps().add(op1);
		fermeeClazz.getOps().add(op2);
		fermeeClazz.getOps().add(op3);
		
		debutClazz.getOps().add(op1);
		debutClazz.getOps().add(op2);
		debutClazz.getOps().add(op3);
		
		finClazz.getOps().add(op1);
		finClazz.getOps().add(op2);
		finClazz.getOps().add(op3);
		
		etat.getOps().add(op1);
		etat.getOps().add(op2);
		etat.getOps().add(op3);
		
		diag.getOps().add(op1);
		diag.getOps().add(op2);
		diag.getOps().add(op3);
		
		
		//diag.getClazzes().add(serveur);
		
		//fin creation diag
		
		//notify
		System.out.println("notify");
		if(notify(mat,diag))
			System.out.println("true");
		else
			System.out.println("false");
		
	
		/*
		//modification
		System.out.println("modification");
		State verrou = SMFactory.eINSTANCE.createState();
		verrou.setNom("verrou");
		
		mat.getEtats().add(verrou);
		
		
		
		DiagClass res = transforme(mat);
		
		//renotify
		System.out.println("notify");
		if(notify(mat,res))
			System.out.println("true");
		else
			System.out.println("false");
		*/
		
		generateCode(diag, mat);
		
		
	}
	
	
	
	
	
	public static boolean notify(MAT sm, DiagClass dc){
		
		boolean found = false;
		
		//regle one
		for(State s : sm.getEtats()){
			for(Clazz c : dc.getClazzes()){
				if(s.getNom().equals(c.getNom()) && c.getClass().getSuperclass().getName().equals("etat"))
					found = true;
			}
			
			if(!found)
				 return false;
			
			found = false;
		}
		
		//regle two
		
		for(Clazz c : dc.getClazzes()){
			if(c.getClass().getSuperclass().getName().equals("etat")){
				
				for(State s : sm.getEtats()){
					if(s.getNom().equals(c.getNom()))
						found = true;
				}
				
				if(!found)
					 return false;
				
				found = false;

			}
			
		}
		
		
		return true;
		
	}
	
	public static String output="out/";
	
	public static void generateCodeServeur(DiagClass diag){
		
		PrintWriter serveur = null;
		try {
			serveur = new PrintWriter(output+"Serveur.java");
		} catch (FileNotFoundException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
		serveur.println("public abstract class Serveur{");
		
		//attributeref
		serveur.println("public State state;");
					
		for(Operation op : diag.getOps()){
			
			serveur.println("public abstract "+op.getNom()+"();" );

		}
			
		serveur.println("public void setEtat(State state){");
		serveur.println("this.state = state;");
		serveur.println("}\n}");
		serveur.close();
	}
	
	public static void generateCodeEtat(DiagClass diag){
		PrintWriter etatFile = null;
		try {
			etatFile = new PrintWriter(output+"State.java");
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		etatFile.println("public abstract class State {");
		
		//attributeref
		etatFile.println("protected Serveur serveur;");
					
		for(Operation op : diag.getOps()){	
			etatFile.println("public abstract "+op.getNom()+"();" );
		}
		etatFile.println("}");
		etatFile.close();
	}
	
	public static void generateCode(DiagClass diag, MAT mat){
		
		System.out.print("Generation code serveur...");
		//GENERATION CODE SERVEUR
		generateCodeServeur(diag);
		//FIN CODE SERVEUR
		System.out.println("done");
		
		System.out.print("Generation code etat...");
		// GENERER CODE STATE
		generateCodeEtat(diag);
		//FIN CODE STATE
		System.out.println("done");
		
		
		for(Clazz c : diag.getClazzes()){
			PrintWriter fileOpen = null;
			try {
				fileOpen = new PrintWriter(output+"Etat"+c.getNom()+".java");
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			fileOpen.println("public class Etat"+c.getNom()+" extends State{");
			
			fileOpen.println("public String nom;");
			
			for(Operation op : diag.getOps()){
				
				String Tg = findOP(mat, op.getNom(), c.getNom());
				if(Tg==null){	
					fileOpen.println("public "+op.getNom()+"() throws Exception{" );
					fileOpen.println("throw new Exception(\"Operation no found\");");
					fileOpen.println("}");
				}
				
				else {
					fileOpen.println("public "+op.getNom()+"(){" );
					fileOpen.println("serveur.setEtat(new Etat"+Tg+"(\""+Tg+"\"));");
					fileOpen.println("}");
				
				}
			}
			
			fileOpen.println("}");
			fileOpen.close();
			
		
				
		}	
				
				
				
			
		
		
		
		
		
	}
	
	
	public static String findOP(MAT mat, String nomOp, String etatDepart){
		for(Transition tr : mat.getTrans()){
			if(tr.getSrc().getNom().equals(etatDepart) && tr.getNom().equals(nomOp))
				return tr.getTg().getNom();
		}
		return null;
	}
	
	
	
	public static DiagClass transforme(MAT m){
		
		DiagClass res = DGFactory.eINSTANCE.createDiagClass();
		Clazz stateclazz = DGFactory.eINSTANCE.createClazz();
		stateclazz.setNom("etat");
		res.getClazzes().add(stateclazz);
		
		
		
		System.out.println("nombre d'etats ="+m.getEtats().size());
		
		for(State s : m.getEtats()){
			
			Clazz newclazz = DGFactory.eINSTANCE.createClazz();
			newclazz.setSuper(res.getSuper());
			newclazz.setNom(s.getNom());
			res.getClazzes().add(newclazz);
						
		}	
		
		return res;
		
		
	}
	
}
